/**
 * 日志处理模块
 */
"use strict";
const radon = require('radon')
	,include = radon.use('Include')
	,getConfig 	= include.config
	,util = include.util
	,url = require('url')
	,child = require('child_process')
	,FS = require('./File');

const LINELIMIT = 10000; // 日志查询行数限制

const mod = include.app.extend({
	getEvents: function(){
		return [
			['view', this.view]
			,['download', this.download]
		];
	}
	// 日志查看
	,view: function* (req, res) {
		let data = req.get();
		// 行数限制
		if(!data.line || +data.line > LINELIMIT) {
			data.line = LINELIMIT;
		}

		// 过滤日志文件
		let logResult = yield Tool.filterLogFile(data);
		if (!logResult || !logResult.success) {
			radon.throw(10000400, [logResult ? logResult.message : ""]);
		}

		// 读取日志文件
		let logBuf = yield logResult.read();
		let conStr = String(logBuf);
		conStr = Tool.formatData(conStr, data.date);

		return {
			content: conStr,
			errNum: (conStr.match(/Error:/g) || []).length // 错误数
		};
	}
	,download: function*(req, res) {
		res.setHeader('content-type', 'application/json;charset=utf-8');
		let data = req.get();
		data = data && data.get;

		// 过滤日志文件
		let logResult = yield Tool.filterLogFile(data);
		if (!logResult || !logResult.success) {
			radon.throw(10000400, [logResult ? logResult.message : ""]);
		}
		
		// 下载日志文件
		let fileName = `${data.logType}_${data.date}${data.line ? '_'+data.line : ''}.log`;
		let ret = yield logResult.read();
		Tool.setHeader(fileName, ret.length);

		return ret;
	}
});

const Tool = {
	// 将日志文件进行条件过滤
	*filterLogFile(data) {
		let ret = {
			success : false,
			logFilePath : '',
			tmpFilePath : '',
		};
		let line = data.line;
		let lineKeyword = data.lineKeyword;
		let date = util.date('Ymd', data.date);
		let type = data.logType;
		let logPath = getConfig('hawk.log_dir');
		let file = logPath ? `${logPath[type]}${date}.log` : util.normalizePath(`/../var/log/${type}_${date}.log`);

		if(yield FS.exists(file)) { // 日志文件
			let target;
			if (line || lineKeyword) { // 没有筛选条件过滤，直接返回文件路径
				target = file.replace('.log', `_tmp${Math.floor(Math.random()*1000)}.log`);

				// 根据筛选条件创建命令行
				let command = this.createCmd(file, target, lineKeyword, line);

				// 执行命令
				try {
					yield Tool.runCmd(command);
				}
				catch(e) {
					util.log(104, 'RunCmd Error: ' + e.stack);
					ret.success = false;
					ret.message = `RunCmd Error. Command is: ${command}`;
					return ret
				}

				ret.tmpFilePath = target;
			} else {
				ret.logFilePath = file;
			}
		}

		// 读取日志文件
		ret.read = function *() {
			let buf;
			let target = this.tmpFilePath || this.logFilePath;
			if (target) {
				buf = yield FS.readFile(target);
				if (buf.length === 0) {
					buf = new Buffer('NO LOG.', 'utf8');
				}

				if (this.tmpFilePath) {
					yield FS.remove(this.tmpFilePath);
				}
			} else {
				buf = new Buffer('NO FILE.', 'utf8');
			}
			return buf;
		};

		ret.success = true;
		return ret;
	},
	formatData(data, date) {
		let remove = [
			'\\x1b\\[41m',
			'\\x1b\\[49m',
			'\\x1b\\[32m',
			'\\x1b\\[36m',
			'\\x1b\\[39m',
			'\\x1b\\[90m',
			util.date('Y-m-d', date) + ' '
		].map(s => '(' + s + ')').join('|');

		remove = new RegExp(remove, 'g');
		data = data.replace(remove, '');

		return data;
	},
	createCmd(file, target, lineKeyword, line) {
		let command = `{line} {keywords} cat> ${target}`;

		// 行
		command = command.replace('{line}', `${line ? "tail -n "+line +" "+ file +" |": ""}`);

		// 关键字
		let keywords = '';
		if (lineKeyword) {
			let keywordsArr = lineKeyword.split("|").filter(Boolean);
			if (!line) {
				keywords += `grep '${keywordsArr.pop()}' ${file}| `;
			}
			keywordsArr.map(word => {
				keywords += `grep '${word}' | `;
			});
		}
		command = command.replace('{keywords}', keywords);

		return command;
	},
	runCmd() {
		let args = [].slice.call(arguments, 0);
		return util.promise(function(done, fail){
			args.push(function(err, data) {
				if (err){
					fail(err);
				}
				else
				{
					done(data);
				}
			});

			child.exec.apply(child, args);
		});
	},
	setHeader(name, length) {
		let header = this.getHeader(name, length);
		let res = radon.getContextData('response');
		for(let head in header) {
			if(header.hasOwnProperty(head)) {
				res.setHeader(head, header[head]);
			}
		}
	},
	getHeader(name, size) {
		return {
			'Content-Disposition': 'attachment;filename=' + encodeURIComponent(name),
			'Content-Length': size,
			'Content-Type': 'application/octet-stream',
			'Content-Transfer-Encoding': 'binary'
		}
	}
};

module.exports = mod;
